package com.fwtai.service.core;

import com.fwtai.bean.PageFormData;
import com.fwtai.bean.SysUser;
import com.fwtai.config.ConfigFile;
import com.fwtai.config.LocalUserId;
import com.fwtai.core.UserDao;
import com.fwtai.entity.User;
import com.fwtai.tool.IdBuilder;
import com.fwtai.tool.ToolClient;
import com.fwtai.tool.ToolJWT;
import com.fwtai.tool.ToolString;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 用户账号
 * @作者 田应平
 * @版本 v1.0
 * @创建时间 2020-03-13 17:24
 * @QQ号码 444141300
 * @Email service@dwlai.com
 * @官网 http://www.fwtai.com
*/
@Service
public class UserService{

  private final UserDao userDao;

  private final BCryptPasswordEncoder passworder;

  final ThreadPoolExecutor executor = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors()*32,76800,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<>(51200),new ThreadPoolExecutor.CallerRunsPolicy()
  );

  public UserService(final UserDao userDao,final BCryptPasswordEncoder passworder){
    this.userDao = userDao;
    this.passworder = passworder;
  }

  // 仅仅获取用户userId的角色和权限,动态鉴权
  public List<String> getRolePermissions(final String userId,final String url){
    final HashMap<String,String> params = new HashMap<String,String>(2);
    params.put("url",url);
    params.put("userId",userId);
    return userDao.getRolePermissions(params);
  }

  /**
   * 通过userName查询用户信息,用户登录
   * @param username
   * @作者 田应平
   * @QQ 444141300
   * @创建时间 2020/5/1 0:54
  */
  public SysUser getUserByUserName(final String username){
    return userDao.getUserByUserName(username);
  }

  /**
   * 通过userId查询用户名
   * @param userId
   * @作者 田应平
   * @QQ 444141300
   * @创建时间 2020/5/1 0:53
  */
  public SysUser getUserById(final String userId){
    return userDao.getUserById(userId);
  }

  public String add(final PageFormData formData){
    final String p_user_name = "user_name";
    final String p_user_password = "user_password";
    final String p_verify_password = "verify_password";
    final String validate = ToolClient.validateField(formData,p_user_name,p_user_password,p_verify_password);
    if(validate != null)return validate;
    final String user_name = formData.getString(p_user_name);
    final String password = formData.getString(p_user_password);
    final String verify = formData.getString(p_verify_password);
    if(!password.equals(verify)){
      return ToolClient.createJsonFail("输入的两次密码不一致");
    }
    final String exist = userDao.queryExistByUser(user_name);
    if(exist != null){
      return ToolClient.createJsonFail(user_name+"用户账号已存在,换个试试");
    }
    formData.remove(p_user_password);
    formData.remove(p_verify_password);
    formData.put("kid",new IdBuilder().getId121L());
    formData.put("password",passworder.encode(password));
    return ToolClient.executeRows(userDao.add(formData));
  }

  public String edit(final PageFormData formData){
    final String p_user_name = "user_name";
    final String p_user_password = "user_password";
    final String p_verify_password = "verify_password";
    final String p_kid = "kid";
    final String validate = ToolClient.validateField(formData,p_user_name,p_user_password,p_verify_password,p_kid);
    if(validate != null)return validate;
    final String user_name = formData.getString(p_user_name);
    final String password = formData.getString(p_user_password);
    final String verify = formData.getString(p_verify_password);
    if(!password.equals(verify)){
      return ToolClient.createJsonFail("输入的两次密码不一致");
    }
    final String exist = userDao.queryExistByUser(user_name);
    if(exist == null){
      return ToolClient.createJsonFail(user_name+"用户账号已不存在");
    }
    formData.remove(p_user_password);
    formData.remove(p_user_name);
    formData.remove(p_verify_password);
    formData.put("password",passworder.encode(password));
    final int rows = userDao.edit(formData);
    return ToolClient.executeRows(rows);
  }

  public String getAllotRole(final PageFormData formData){
    final String loginId = LocalUserId.get();
    final String userId = formData.getString("userId");
    if(ConfigFile.SUPER_KEY.equals(loginId)){
      return ToolClient.queryJson(userDao.getSuperAllotRole(userId));
    }else{
      return ToolClient.queryJson(userDao.getUserIdAllotRole(loginId,userId));
    }
  }

  public User queryUser(final String userName){
    return userDao.queryUser(userName);
  }

  public void updateErrors(final String userName){
    userDao.updateErrors(userName);
  }

  public void updateLoginTime(final String userName){
    userDao.updateLoginTime(userName);
  }

  public String delById(final PageFormData formData){
    final String p_kid = "id";
    final String validate = ToolClient.validateField(formData,p_kid);
    if(validate != null)return validate;
    final String kid = formData.getString(p_kid);
    if(ConfigFile.SUPER_KEY.equals(kid)){
      return ToolClient.createJson(ConfigFile.code204,"超级管理员不能删除");
    }
    final String user_name = userDao.queryExistById(kid);//查询是否存在
    if(user_name == null){
      return ToolClient.createJsonFail("用户账号已不存在");
    }
    final int rows = userDao.delById(kid);
    return ToolClient.executeRows(rows);
  }

  //批量分配角色
  public String saveAllotRole(final PageFormData formData){
    final String p_type = "type";
    final String validate = ToolClient.validateField(formData,p_type);
    if(validate != null)return validate;
    final String fieldInteger = ToolClient.validateInteger(formData,p_type);
    if(fieldInteger != null)return fieldInteger;
    final int type = formData.getInteger(p_type);
    if(type == 1){
      final String userId = formData.getString("userId");
      final String kids = formData.getString("kids");
      if(userId == null){
        return ToolClient.jsonValidateField();
      }
      final String exist_key = userDao.queryExistById(userId);//查询是否存在
      if(exist_key == null){
        return ToolClient.createJsonFail("用户账号已不存在");
      }
      final ArrayList<String> listRoles = ToolString.keysToList(kids);
      if(listRoles == null || listRoles.size() <= 0){
        final int rows = userDao.delAllotRole(userId);//清空
        return ToolClient.executeRows(rows);
      }else{
        final ArrayList<HashMap<String,String>> lists = new ArrayList<HashMap<String,String>>();
        final Iterator<String> iterator = listRoles.iterator();
        while(iterator.hasNext()){
          final HashMap<String,String> map = new HashMap<String,String>();
          map.put("role_id",iterator.next());
          map.put("user_id",userId);
          lists.add(map);
        }
        final int rows = userDao.saveAllotRole(userId,lists);//清空之前的角色,重新分配角色
        return ToolClient.executeRows(rows);
      }
    }
    if(type == 2){
      final String userIds = formData.getString("userIds");
      final String kids = formData.getString("kids");
      if(userIds == null){
        return ToolClient.createJsonFail("请选择要分配角色的账号");
      }
      final ArrayList<String> listUserIds = ToolString.keysToList(userIds);
      final ArrayList<String> listRoles = ToolString.keysToList(kids);
      if(listRoles == null || listRoles.size() <= 0){
        final int rows = userDao.delBatchUserRole(listUserIds);
        return ToolClient.executeRows(rows);
      }else{
        final ArrayList<HashMap<String,String>> listMaps = new ArrayList<HashMap<String,String>>();
        final Iterator<String> iteratorUser = listUserIds.iterator();
        while(iteratorUser.hasNext()){
          final Iterator<String> iteratorRoles = listRoles.iterator();
          final String uid = iteratorUser.next();
          while(iteratorRoles.hasNext()){
            final HashMap<String,String> map = new HashMap<String,String>();
            map.put("role_id",iteratorRoles.next());
            map.put("user_id",uid);
            listMaps.add(map);
          }
        }
        final int rows = userDao.saveBatchUserRole(listUserIds,listMaps);
        return ToolClient.executeRows(rows);
      }
    }
    return ToolClient.jsonValidateField();
  }

  public String saveOwnMenu(final PageFormData formData){
    final String p_userId = "userId";
    final String validate = ToolClient.validateField(formData,p_userId);
    if(validate != null)return validate;
    final String kids = formData.getString("kids");
    final String userId = formData.getString(p_userId);
    final ArrayList<String> listMenus = ToolString.keysToList(kids);
    if(listMenus == null || listMenus.size() <= 0){
      final int rows = userDao.delOwnMenu(userId);
      return ToolClient.executeRows(rows,"操作成功","尚未分配私有菜单");
    }else{
      final ArrayList<HashMap<String,String>> listMaps = new ArrayList<HashMap<String,String>>();
      final Iterator<String> iterator = listMenus.iterator();
      while(iterator.hasNext()){
        final HashMap<String,String> map = new HashMap<String,String>();
        map.put("menu_id",iterator.next());
        map.put("user_id",userId);
        listMaps.add(map);
      }
      final int rows = userDao.saveOwnMenu(userId,listMaps);
      return ToolClient.executeRows(rows);
    }
  }

  public String delByKeys(final PageFormData formData){
    final String p_ids = "ids";
    final String validate = ToolClient.validateField(formData,p_ids);
    if(validate != null)return validate;
    final String ids = formData.getString(p_ids);
    final ArrayList<String> lists = ToolString.keysToList(ids);
    if(lists == null || lists.size() <= 0){
      return ToolClient.createJsonFail("请选择要删除的数据");
    }
    lists.remove(ConfigFile.SUPER_KEY);
    final int rows = userDao.delByKeys(lists);
    return ToolClient.executeRows(rows,"操作成功","用户已不存在,刷新重试");
  }

  public String editEnabled(final PageFormData formData){
    final String p_disable = "disable";
    final String p_enabled = "enabled";
    final String p_userId = "userId";
    final String validate = ToolClient.validateField(formData,p_disable,p_enabled,p_userId);
    if(validate != null)return validate;
    final String fieldInteger = ToolClient.validateInteger(formData,p_disable,p_enabled);
    if(fieldInteger != null)return fieldInteger;
    final String kid = formData.getString(p_userId);
    if(ConfigFile.SUPER_KEY.equals(kid)){
      return ToolClient.createJson(ConfigFile.code204,"不能操作超级管理员");
    }
    final String user_name = userDao.queryExistById(kid);//查询是否存在
    if(user_name == null){
      return ToolClient.createJsonFail("账号已不存在");
    }
    final int rows = userDao.editEnabled(formData);
    return ToolClient.executeRows(rows);
  }

  public boolean checkLogin(final String username,final String rawPassword){
    final String password = userDao.queryLogin(username);
    if(password == null)return false;
    return passworder.matches(rawPassword,password);
  }

  public String listData(PageFormData formData){
    try {
      formData = ToolClient.dataTableMysql(formData);
      if(formData == null)return ToolClient.jsonValidateField();
      final String userId = LocalUserId.get();
      formData.put("userId",userId);
      if(ConfigFile.SUPER_KEY.equals(userId)){
        formData.put("keySuper",userId);
      }
      final HashMap<String,Object> map = userDao.listData(formData);
      return ToolClient.dataTableOK((List<Object>)map.get(ConfigFile.rows),map.get(ConfigFile.total));
    } catch (Exception e){
      e.printStackTrace();
      return ToolClient.dataTableException(formData.get("sEcho"));
    }
  }

  //根据指定userid获取菜单用于分配私有菜单
  public String getOwnMenu(final PageFormData formData){
    final String p_userId = "userId";
    final String validate = ToolClient.validateField(formData,p_userId);
    if(validate != null)return validate;
    final String userId = formData.getString(p_userId);
    final String loginId = LocalUserId.get();
    if(ConfigFile.SUPER_KEY.equals(loginId)){
      return ToolClient.queryJson(userDao.getOwnMenuForSuper(userId));
    }
    formData.put("loginId",loginId);
    return ToolClient.queryJson(userDao.getOwnMenuForLogin(formData));
  }

  //查看指定userid权限菜单数据
  public String getMenuData(final PageFormData formData){
    final String p_userId = "userId";
    final String validate = ToolClient.validateField(formData,p_userId);
    if(validate != null)return validate;
    final String userId = formData.getString(p_userId);
    return ToolClient.queryJson(userDao.getMenuData(userId));
  }

  //仅保存userId,userName,roles 即可,并行处理
  public HashMap<String,String> buildToken(final String userId){
    final HashMap<String,String> token = new HashMap<>(2);
    CompletableFuture.allOf(
      CompletableFuture.runAsync(()->{
        token.put(ConfigFile.REFRESH_TOKEN,ToolJWT.expireRefreshToken(userId));
      },executor),
      CompletableFuture.runAsync(()->{
        token.put(ConfigFile.ACCESS_TOKEN,ToolJWT.expireAccessToken(userId));
      },executor)
    ).join();
    return token;
  }

  /**自行修改密码*/
  public String editPassword(final PageFormData formData){
    final String p_original_password = "original_password";
    final String p_new_password = "new_password";
    final String p_verify_password = "verify_password";
    final String validate = ToolClient.validateField(formData,p_original_password,p_new_password,p_verify_password);
    if(validate != null)return validate;
    final String original_password = formData.getString(p_original_password);
    final String password = formData.getString(p_new_password);
    final String verify = formData.getString(p_verify_password);
    if(!password.equals(verify)){
      return ToolClient.createJsonFail("输入的两次密码不一致");
    }
    final String userId = LocalUserId.get();
    final String pwd = userDao.getPassword(userId);
    final boolean bl = passworder.matches(original_password,pwd);
    if(!bl){
      return ToolClient.createJsonFail("您输入的原始密码不正确");
    }
    formData.put("userId",userId);
    formData.put("password",passworder.encode(password));
    return ToolClient.executeRows(userDao.editPassword(formData),"修改成功","修改失败,稍候重试");
  }

  public String updateForget(final PageFormData formData,final String password){
    formData.put("password",passworder.encode(password));
    final int rows = userDao.updateForget(formData);
    return ToolClient.executeRows(rows,"新密码已生效","设置新密码失败,稍候重试");
  }
}